package com.remoter.basic.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author			koko
 * @date 			2017-08-08 13:02:47
 * @description 	类功能说明
 */
public class ServiceLoader<T> {
	
	/**
	 * 可自定义Scope,实现不同的扩展点的实例化模式
	 * @author koko
	 *
	 */
	public enum Scope{
		PROTOTYPE,//实例模式
		SINGLETON//单例模式
	}
	
	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	public @interface SPI{
		public String value() default "";//当前扩展点默认的名称
		public Scope scope() default Scope.SINGLETON;//当前扩展点默认实例化方式 单例
	}
	
	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	public @interface MetaName{
		public String value();//自定义扩展点名称
	}
	
	/**
	 * 指定类型的扩展点对应的ServiceLoader实例,缓存到当前map中,避免重复实例化及快速检索
	 */
	private static final ConcurrentHashMap<String,ServiceLoader<?>> D_LOADERS = new ConcurrentHashMap<String,ServiceLoader<?>>();
	/**
	 * 默认搜索配置文件的路径
	 */
	private static final String D_SERVICES = "META-INF/services/";
	private static final String D_INTERNAL = "META-INF/internal/";
	
	private final Class<T> type;//当前ServiceLoader对应的接口类型
	private final String name;//当前ServiceLoader默认的扩展点名称,没有则为null
	private final Scope scope;//当前ServiceLoader实例化采用的方式
	private final ConcurrentHashMap<String,Class<T>> S_CLASSES = new ConcurrentHashMap<String,Class<T>>();//存储扩展点实现及对应的class映射
	private final ConcurrentHashMap<String,T> S_INSTANCE = new ConcurrentHashMap<String,T>();//存储扩展点实现及对应的instance映射
	
	/**
	 * 私有构造函数,禁止外部实例化
	 * @param type
	 */
	private ServiceLoader(Class<T> type){
		if(null == type){
			throw new IllegalArgumentException("type is null");
		}
		if(!type.isInterface()){
			throw new IllegalArgumentException("type must interface");
		}
		SPI spi = type.getAnnotation(SPI.class);
		if(null == spi){
			throw new IllegalArgumentException("type has no @SPI annotation");
		}
		this.type = type;
		this.name = StringUtil.isBlank(spi.value()) ? null : spi.value();
		this.scope = spi.scope();
		this.refresh();
	}
	
	/**
	 * 刷新具体配置文件及内容
	 */
	private void refresh(){
		Map<String,Class<T>> classes = new HashMap<String,Class<T>>();
		this.loadFile(D_SERVICES,classes);
		this.loadFile(D_INTERNAL,classes);
		this.S_CLASSES.putAll(classes);
	}
	
	/**
	 * 根据传入的参数刷新配置文件
	 * @param path
	 * @param classes
	 */
	private void loadFile(String path,Map<String,Class<T>> classes){
		try{
			String className = this.type.getName();
			String filePath = String.format("%s%s",path,className);
			Enumeration<URL> urls = null;
			ClassLoader classLoader = ServiceLoader.class.getClassLoader();
			if(null == classLoader){
				urls = ClassLoader.getSystemResources(filePath);
			}else{
				urls = classLoader.getResources(filePath);
			}
			if(null == urls){
				return;
			}
			while(urls.hasMoreElements()){
				URL url = urls.nextElement();
				try(
					InputStreamReader inputStreamReader = new InputStreamReader(url.openStream());
					BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
				){
					String line = null;
					String[] temp = null;
					String name = null;
					String clazz = null;
					int index = -1;
					while((line = bufferedReader.readLine()) != null){
						if(StringUtil.isBlank(line)){
							continue;
						}
						index = line.indexOf("=");
						if(index > 0){
							temp = line.split("=");
							name = temp[0].trim();
							clazz = temp[1].trim();
							if(StringUtil.isBlank(clazz)){
								continue;
							}
							if(StringUtil.isBlank(name)){
								name = clazz;
							}
						}else{
							name = clazz = line;
						}
						try{
							@SuppressWarnings("unchecked")
							Class<T> c = (Class<T>)Class.forName(clazz);
							if(this.type.isAssignableFrom(c)){
								MetaName metaName = c.getAnnotation(MetaName.class);
								if(null != metaName){
									name = metaName.value();
								}
								classes.put(name,c);
							}else{
								throw new IllegalArgumentException(clazz + " must implements " + this.type.getName());
							}
						}catch(Exception e){
							e.printStackTrace();
							continue;
						}finally{
							temp = null;
							index = -1;
							name = null;
							clazz = null;
						}
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * 根据扩展点名称获取具体实例
	 * @param name
	 * @return
	 */
	public T getService(String name){
		if(StringUtil.isBlank(name)){
			name = this.name;
		}
		if(StringUtil.isBlank(name)){
			return null;
		}
		Class<T> clazz = S_CLASSES.get(name);
		if(null == clazz){
			return null;
		}
		if(this.scope == Scope.PROTOTYPE){//这里需要根据注解的scope区分出实例化的方式
			return this.createInstance(clazz);
		}
		T result = S_INSTANCE.get(name);
		if(null == result){
			result = this.createInstance(clazz);
			if(null == result){
				return null;
			}
			S_INSTANCE.put(name,result);
		}
		return result;
	}
	
	/**
	 * 实例化指定class,注意:必须包含无参构造函数,否则无法实例化
	 * @param clazz
	 * @return
	 */
	private T createInstance(Class<T> clazz){
		T result = null;
		try{
			result = clazz.newInstance();
		}catch(Throwable t){
			t.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 获取指定接口的ServideLoader实例,存在为空的可能
	 * @param type
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <E> ServiceLoader<E> getServiceLoader(Class<E> type){
		if(null == type){
			throw new IllegalArgumentException("type is null");
		}
		String name = type.getName();
		ServiceLoader<E> serviceLoader = null;
		if(!D_LOADERS.containsKey(name)){
			D_LOADERS.putIfAbsent(name,new ServiceLoader<E>(type));
		}
		serviceLoader = (ServiceLoader<E>)D_LOADERS.get(name);
		return serviceLoader;
	}
	
	/**
	 * 快捷方法,直接获取指定接口的扩展点实例
	 * @param type
	 * @param name
	 * @return
	 */
	public static <E> E getService(Class<E> type,String name){
		ServiceLoader<E> serviceLoader = getServiceLoader(type);
		if(null == serviceLoader){
			throw new IllegalArgumentException("ServiceLoader not found");
		}
		return serviceLoader.getService(name);
	}
	
	/**
	 * 快捷方法,直接获取指定接口的扩展点实例
	 * @param type
	 * @return
	 */
	public static <E> E getService(Class<E> type){
		return getService(type,null);
	}
	
}